<template>
  <div class="vc-saturation"
       :style="{background: bgColor}"
       ref="container"
       @mousedown="handleMouseDown"
       @touchmove="handleChange"
       @touchstart="handleChange">
    <div class="vc-saturation--white"></div>
    <div class="vc-saturation--black"></div>
    <div class="vc-saturation-pointer" :style="{top: pointerTop, left: pointerLeft}">
      <div class="vc-saturation-circle"></div>
    </div>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, ref, Ref } from 'vue'
import clamp from 'clamp'
import throttle from 'lodash.throttle'

export default defineComponent({
  name: 'Saturation',
  props: {
    colors: {
      type: Object,
      required: true,
    },
  },
  emits: ['change'],
  setup(props, { emit }) {
    const container: Ref = ref(null)

    const doThrottle = throttle((fn, data) => {
      fn(data)
    }, 20, { 'leading': true, 'trailing': false })

    const onChange = (param: any) => {
      emit('change', param)
    }

    const handleChange = (e: any, skip = false) => {
      !skip && e.preventDefault()
      const containerElement = container.value
      if (!containerElement) {
        // for some edge cases, container may not exist. see #220
        return
      }
      const containerWidth = containerElement.clientWidth
      const containerHeight = containerElement.clientHeight

      const xOffset = containerElement.getBoundingClientRect().left + window.pageXOffset
      const yOffset = containerElement.getBoundingClientRect().top + window.pageYOffset
      const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0)
      const pageY = e.pageY || (e.touches ? e.touches[0].pageY : 0)
      const left = clamp(pageX - xOffset, 0, containerWidth)
      const top = clamp(pageY - yOffset, 0, containerHeight)
      const saturation = left / containerWidth
      const bright = clamp(-(top / containerHeight) + 1, 0, 1)

      doThrottle(onChange, {
        h: props.colors.hsv.h,
        s: saturation,
        v: bright,
        a: props.colors.hsv.a,
        source: 'hsva',
      })
    }

    const handleMouseDown = (e: Event) => {
      window.addEventListener('mousemove', handleChange)
      window.addEventListener('mouseup', handleChange)
      window.addEventListener('mouseup', handleMouseUp)
    }
    const handleMouseUp = (e: Event) => {
      unbindEventListeners()
    }
    const unbindEventListeners = () => {
      window.removeEventListener('mousemove', handleChange)
      window.removeEventListener('mouseup', handleChange)
      window.removeEventListener('mouseup', handleMouseUp)
    }

    return {
      container,
      bgColor: computed(() => `hsl(${props.colors.hsv.h}, 100%, 50%)`),
      pointerTop: computed(() => (-(props.colors.hsv.v * 100) + 1) + 100 + '%'),
      pointerLeft: computed(() => props.colors.hsv.s * 100 + '%'),
      handleChange,
      handleMouseDown,
    }
  },
})
</script>